<?php

namespace App\Http\Services\Api\V1\App\Customer;

use AlipaySystemOauthTokenRequest;
use AlipayUserInfoShareRequest;
use AopClient;
use App\Exceptions\ApiErrCode;
use App\Exceptions\ApiException;
use App\Models\Customers\AlipayUser;
use App\Models\Setting;
use App\Services\Utils\TimeHelper;
use Service\AlipayOpenPlatform\AopFactory;

class AliPayService
{
    const OAUTH_TYPE_ALIPAY_APP = 'alipay_app';
    const OAUTH_ALIPAY_APP_ID = 'oauth_alipay_app_app_id'; // 支付宝登录app_id
    const OAUTH_ALIPAY_APP_PUBLIC_KEY = 'oauth_alipay_app_public_key'; // 支付宝登录app_public_key
    const OAUTH_ALIPAY_APP_PRIVATE_KEY = 'oauth_alipay_app_private_key'; // 支付宝登录app_private_key
    const OAUTH_ALIPAY_APP_PID = 'oauth_alipay_app_pid'; // 支付宝登录pid

    /**
     * @return \Illuminate\Database\Eloquent\Model
     * @throws \Exception
     */
    public function getOauthUser()
    {
        $alipay_config = $this->productionAop();
        $aop = (new AopFactory)->productionAppAop($alipay_config);
        $access_token = $this->queryAccessToken($aop);
        $user_info = $this->queryUserInfo($aop, $access_token);
        $user_data = $this->normalizeUserData($user_info);
        $alipay_user = $this->updateOrCreateUser($user_data);

        return $alipay_user;
    }

    /**
     * @return string
     */
    public function getAppsign()
    {
        $alipay_config = $this->productionAop();
        $aop = (new AopFactory)->productionAppAop($alipay_config);

        $params = $this->getAliPaySignParams($aop->appId, $aop->pid);

        $params['sign'] = $aop->generateSign($params, "RSA2");

        $requestUrl = '';
        foreach ($params as $sysParamKey => $sysParamValue) {
            $requestUrl .= "$sysParamKey=" . urlencode($sysParamValue) . "&";
        }

        return trim($requestUrl, '&');
    }

    /**
     * @return mixed
     */
    public function productionAop()
    {
        $alipay_config['app_id'] = Setting::getSettingSpecifyValue(self::OAUTH_ALIPAY_APP_ID);
        $alipay_config['app_public_key'] = Setting::getSettingSpecifyValue(self::OAUTH_ALIPAY_APP_PUBLIC_KEY);
        $alipay_config['app_private_key'] = Setting::getSettingSpecifyValue(self::OAUTH_ALIPAY_APP_PRIVATE_KEY);
        $alipay_config['pid'] = Setting::getSettingSpecifyValue(self::OAUTH_ALIPAY_APP_PID);

        return $alipay_config;
    }

    /**
     * @param $app_id
     * @return array
     */
    private function getAliPaySignParams($app_id, $pid)
    {
        return [
            'apiname'    => 'com.alipay.account.auth',
            'method'     => 'alipay.open.auth.sdk.code.get',
            'app_id'     => $app_id,
            'app_name'   => 'mc',
            'biz_type'   => 'openservice',
            'pid'        => $pid,            // 后台要配置
//            'pid'        => '2088021952506112', // 后台要配置
            'product_id' => 'APP_FAST_LOGIN',
            'scope'      => 'kuaijie',
            'target_id'  => TimeHelper::microTimeSerial(), // 随机数
            'auth_type'  => 'AUTHACCOUNT',
            'sign_type'  => 'RSA2',
        ];
    }


    /**
     * @param AopClient $aop
     *
     * @return null
     * @throws \Exception
     */
    protected function queryAccessToken(AopClient $aop)
    {
        $oauth = new AlipaySystemOauthTokenRequest();
        $oauth->setCode(request()->get('code'));
        $oauth->setGrantType("authorization_code");

        /**
         * $res = (object) [
         * "alipay_system_oauth_token_response" => [
         * "access_token"   => "authusrBe57af8e3346246af96740cafca31aF06",
         * "alipay_user_id" => "20881075931959181964981560611106",
         * "expires_in"     => 1296000,
         * "re_expires_in"  => 2592000,
         * "refresh_token"  => "authusrBaecf10cc7a394492910db5f8648f8C06",
         * "user_id"        => "2088102081601069",
         * ],
         * "sign"  => "XgdFCnUD...",
         * ];
         */
        $res = $aop->execute($oauth);
        $access_token = isset($res->alipay_system_oauth_token_response->access_token)
            ? $res->alipay_system_oauth_token_response->access_token
            : null;

        if (! $access_token) {
            throw new ApiException(ApiErrCode::WECHAT_USER_NOT_FOUND, trans('customer.unable_to_generate_token'));
        }

        return $access_token;
    }

    /**
     * @param AopClient $aop
     * @param string $access_token
     *
     * @return mixed
     * @throws \Exception
     */
    protected function queryUserInfo(AopClient $aop, $access_token)
    {
        $userInfoRequest = new AlipayUserInfoShareRequest();
        /**
         * $user_info = [
         * 'alipay_user_info_share_response' =>
         * [
         * 'code'                 => '10000',
         * 'msg'                  => 'Success',
         * 'avatar'               => 'https://tfs.alipayobjects.com/images/partner/T1VCNpXj4cXXXXXXXX',
         * 'city'                 => '广州市',
         * 'gender'               => 'm',
         * 'is_certified'         => 'T',
         * 'is_student_certified' => 'F',
         * 'nick_name'            => '智翔',
         * 'province'             => '广东省',
         * 'user_id'              => '2088102081601069',
         * 'user_status'          => 'T',
         * 'user_type'            => '2',
         * ],
         * 'sign'                            => 'MuUIX...',
         * ];
         */
        $user_info = $aop->execute($userInfoRequest, $access_token);
        $user_id = isset($user_info->alipay_user_info_share_response->user_id)
            ? $user_info->alipay_user_info_share_response->user_id
            : null;

        if (! $user_id) {
            throw new ApiException(ApiErrCode::WECHAT_USER_NOT_FOUND, trans('customer.alipay_user_not_found'));
        }

        return (array) $user_info->alipay_user_info_share_response;
    }

    /**
     * @param $user_info
     *
     * @return array
     */
    protected function normalizeUserData($user_info)
    {
        $user_data = array_only($user_info, [
            'avatar', 'city', 'gender', 'is_certified', 'is_student_certified',
            'nick_name', 'province', 'user_id', 'user_status', 'user_type',
        ]);

        return $user_data;
    }

    /**
     * @param $user_data
     * @return \Illuminate\Database\Eloquent\Model
     */
    protected function updateOrCreateUser($user_data)
    {
        $alipay_user = (new AlipayUser)->firstOrCreate(['user_id' => $user_data['user_id']], $user_data);

        return $alipay_user;
    }
}